package uk.ac.nott.cs.g53dia;

/**
 * A clump of flowers which a bee can harvest for energy.
 * 
 * @author Neil Madden
 */

/*
 * Copyright (c) 2003 Stuart Reeves.
 * Copyright (c) 2003-2005 Neil Madden.
 * Copyright (c) 2010 University of Nottingham.
 * 
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

public class Flower extends DefaultCell {
    /**
     * The type of this flower.
     */
    private int type;

    /**
     * Timestep for the previous call to collect.
     */
    private long lastTimestep = -1;
    
    /**
     * A counter of the number of calls to collect during a given timestep
     */
    private int countCollections;
    
        
    /**
     * Number of flowers in this clump.
     */
    private long numFlowers;
    /**
     * Number of different types.
     */
    final static int NUM_TYPES = 5;
    /* The statistics for each type */
    /**
     * Maximum yield of each type of flower.
     */
     private static int[] maxYield = {
         10,
         1,
         8,
         4,
         6
     };
     /**
      * Maximum number of flowers in a clump;
      */
     final static int MAX_FLOWERS_IN_CLUMP = 10;
     /**
      * Rate at which flowers regenerate nectar after being harvested. (Currently not used)
      */
    final static int REGENERATION_RATE = 1;
     /**
      * Nominal time of day at which maximum yield occurs.
      */
     private double[] yieldPeakTime = {
         0.20,
         0.50,
         0.50,
         0.70,
         0.80
     };
     
     /**
      *Duration for which peak yield is sustained.
      */
     private double[] yieldPeakDuration = {
    		 0.10,
    		 0.80,
    		 0.20,
    		 0.30,
    		 0.10,
     };

     /**
      * How quickly the peak yield is achieved
      */

     
     private double[] yieldApproachRate = {
    	20.00,
    	20.00,
    	20.00,
    	 2.00,
    	20.00
     };
     
     /**
      * How quickly the peak yield falls off
      */
     private double[] yieldDecayRate = {
    	0.10,
    	0.10,
    	0.10,
    	2.00,
    	0.10
     };
     /**
      * Set up a clump of flowers.
      */
    public Flower(int type, int num, Point point) {
    
    	super(point);
    	
        if (type < 0 || type >= NUM_TYPES) {
            type = (int)(Math.random() * NUM_TYPES);
        }
        this.type = type;

        if (num <= 0 || num > MAX_FLOWERS_IN_CLUMP) {
            num = (int)(Math.random() * MAX_FLOWERS_IN_CLUMP);
        }
        this.numFlowers = num;
    }

    /**
     * Calculate the current yield of the flower. This is based on 
     * the time of day.
     * @param timestep Current timestep.
     * @return The amount of nectar available.
     */
    int getYield(long timestep) {
        /*
         * To calculate the yield at a given time of day, we want to take into
         * account the maximum yield of this flower type, and the time of day
         * at which the flower is at that maximum. The function should produce
         * a graph approximating a distribution like:
         *
         * yield
         * ^
         * |       .
         * |      ' '.
         * |     '    .
         * |    '      '.
         * |  .'         `-.
         * |.'              `'-......
         * +--------------------------> time
         * 0           5000          10000
         *
         * The function starts at a low value and rises to its peak at the
         * correct time of day, but then falls off to a low value again by the
         * end of the day.
         *
         */
        long timeofday = (timestep % Environment.DAY_LENGTH);
        double yield = 0.0;
        
        double yieldPeakStart = (yieldPeakTime[type]-(yieldPeakDuration[type]/2.0)) * Environment.DAY_LENGTH;
        double yieldPeakEnd = (yieldPeakTime[type]+(yieldPeakDuration[type]/2.0)) * Environment.DAY_LENGTH;
        
        if (timeofday < yieldPeakStart) {
            // before peak time
            yield = (maxYield[type] / Math.pow(yieldPeakStart,yieldApproachRate[type]) ) * Math.pow(timeofday,yieldApproachRate[type]);
        } else if((yieldPeakStart <= timeofday) && (timeofday <= yieldPeakEnd)) {
            // during peak time
            yield = maxYield[type];
        } else {
        	// after peak time
        	yield = maxYield[type] -(maxYield[type] / Math.pow((Environment.DAY_LENGTH-yieldPeakEnd),yieldDecayRate[type])) * Math.pow((timeofday - yieldPeakEnd),yieldDecayRate[type]);
        }
        return (int)yield; 
    }

    /**
     * Collect nectar from this flower and give to bee. Used by the
     * environment. Should not be called by a bee directly.
     * @param ts Current simulation timestep.
     * @return The amount of nectar harvested by the bee.
     */
    int collect(long ts) {
    	
    	int yield = 0;
    	
    	if (lastTimestep != ts) {
    		//first call in this timestep
    		countCollections = 0;
    		lastTimestep = ts;
    		yield = getYield(ts);
    	}
    	else {
    		countCollections++;
    		if (countCollections >= numFlowers) {
    			//Too many collections in this timestep - no more yield!
    			yield = 0;
    		}
    		else {
    			yield = getYield(ts);
    		}
    		
    	}
        
        return yield;
    }

    /**
     * Get the type of this flower.
     */
    public int getType() {
        return type;
    }
    /**
     * Get number of flowers in this bunch.
     */
    public long getNumFlowers() {
        return numFlowers;
    }
}
